/*
 *  Copyright (c) 2011 Leibniz Institute of Plant Genetics and Crop Plant Research (IPK), Gatersleben, Germany.
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the GNU Lesser Public License v2.1
 *  which accompanies this distribution, and is available at
 *  http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 *
 *  Contributors:
 *      Leibniz Institute of Plant Genetics and Crop Plant Research (IPK), Gatersleben, Germany - RMI Client, FileChooser and WebDAV
 */
package de.ipk_gatersleben.bit.bi.edal.webdav.wrapper.primary_data;

import java.io.IOException;
import java.io.OutputStream;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.security.AccessControlException;
import java.util.Map;

import io.milton.http.Auth;
import io.milton.http.Request;
import io.milton.resource.CollectionResource;
import io.milton.resource.DeletableResource;
import io.milton.resource.GetableResource;
import io.milton.resource.MoveableResource;
import io.milton.http.Range;
import io.milton.http.Request.Method;
import io.milton.http.exceptions.BadRequestException;
import io.milton.http.exceptions.ConflictException;
import io.milton.http.exceptions.NotAuthorizedException;
import io.milton.http.exceptions.NotFoundException;

import de.ipk_gatersleben.bit.bi.edal.primary_data.file.PrimaryDataDirectoryException;
import de.ipk_gatersleben.bit.bi.edal.primary_data.file.PrimaryDataEntityVersionException;
import de.ipk_gatersleben.bit.bi.edal.primary_data.file.PrimaryDataFileException;
import de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.DataFormat;
import de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.DataSize;
import de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.EnumDublinCoreElements;
import de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.MetaDataException;
import de.ipk_gatersleben.bit.bi.edal.primary_data.security.EdalAuthenticateException;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientDataManager;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientPrimaryDataEntityVersion;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientPrimaryDataFile;
import de.ipk_gatersleben.bit.bi.edal.webdav.wrapper.FileSystemHandler;

/**
 * A resource representing a PrimaryDataFile.
 * 
 * @author benz
 * 
 */

public class PrimaryDataFileResource extends PrimaryDataEntityResource
		implements GetableResource, DeletableResource, MoveableResource {

	// the primary data represented by this resource
	private ClientPrimaryDataFile file;
	// revision of the version represented by this resource
	// the name of this resource
	private String name;

	public PrimaryDataFileResource(String path,
			FileSystemHandler fileSystemHandler) throws RemoteException,
			PrimaryDataDirectoryException, NotBoundException,
			EdalAuthenticateException {
		super(path, fileSystemHandler);
		if (entity != null) {
			file = (ClientPrimaryDataFile) entity;
			this.name = this.file.getName();
		}
	}

	@Override
	public boolean authorise(Request request, Method method, Auth auth) {
		boolean b = super.authorise(request, method, auth);
		if (entity != null) {
			file = (ClientPrimaryDataFile) entity;
			try {
				this.name = this.file.getName();
			} catch (RemoteException e) {
				ClientDataManager.logger
						.fatal("Failed to load/initialize FileSystemHandler: "
								+ e.getMessage());
			}
		}
		return b;
	}

	/**
	 * Returns the file name.
	 * 
	 * 
	 * @return the file name.
	 */
	@Override
	public String getName() {
		return name;
	}

	/**
	 * Sends the content of a virtual version file to a requesting client.
	 */
	@Override
	public void sendContent(final OutputStream out, Range range,
			Map<String, String> params, String contentType) throws IOException,
			NotAuthorizedException, BadRequestException, NotFoundException {
		try {
			ClientPrimaryDataEntityVersion v = file.getCurrentVersion();
			if (v.getRevision() > 0L && !v.isDeleted()) {
				file.switchCurrentVersion(v);
				file.read(out);
			}
		} catch (PrimaryDataFileException e) {
			ClientDataManager.logger.error("Failed to send content of: " + file
					+ "\nReason" + e.toString());
		} catch (AccessControlException e) {
			ClientDataManager.logger.error("Failed to send content of: " + file
					+ "\nReason" + e.toString());
		} catch (PrimaryDataEntityVersionException e) {
			ClientDataManager.logger.error("Failed to send content of: " + file
					+ "\nReason" + e.toString());
		}
	}

	@Override
	public Long getContentLength() {
		DataSize size = null;
		try {
			size = file.getCurrentVersion().getMetaData()
					.getElementValue(EnumDublinCoreElements.SIZE);
		} catch (RemoteException e) {
			ClientDataManager.logger.error("Failed to get content-length of: "
					+ file + "\nReason" + e.toString());
		} catch (MetaDataException e) {
			ClientDataManager.logger.error("Failed to get content-length of: "
					+ file + "\nReason" + e.toString());
		} catch (AccessControlException e) {
			ClientDataManager.logger.error("Failed to get content-length of: "
					+ file + "\nReason" + e.toString());
		}

		return size.getFileSize();
	}

	@Override
	public String getContentType(String accepts) {
		String type = "default";

		try {
			DataFormat dataType = (DataFormat) file.getMetaData()
					.getElementValue(EnumDublinCoreElements.FORMAT);
			type = dataType.getMimeType();
			return type;
		} catch (RemoteException e) {
			ClientDataManager.logger.error("Failed to get content-type of: "
					+ file + "\nReason" + e.toString());
		} catch (MetaDataException e) {
			ClientDataManager.logger.error("Failed to get content length of: "
					+ file + "\nReason" + e.toString());
		}

		return type;
	}

	@Override
	public Long getMaxAgeSeconds(Auth auth) {
		return null;
	}

	@Override
	public void delete() throws NotAuthorizedException, ConflictException,
			BadRequestException {
		try {
			// System.out.println("delete action in "+this.getClass().getName()+",file:"+file.getPath()+","+file.getName());
			/*
			 * if (this.file.getCurrentVersion().compareTo(
			 * this.file.getVersions().last()) != 0) {
			 * FileSystemHandler.getEntityVersion(file, this.file.getVersions()
			 * .last().getRevision()); }
			 */
			// System.out.println("delete action in "+this.getClass().getName()+",version:"+version);
			fileSystemHandler.removecache(file.getPath());
			if (!this.file.getCurrentVersion().isDeleted()) {
				file.delete();
			}

		} catch (RemoteException e) {
			ClientDataManager.logger
					.error("Failed to delete PrimaryDataFileResource: " + file
							+ "\nReason" + e.toString());
		} catch (PrimaryDataEntityVersionException e) {
			ClientDataManager.logger
					.error("Failed to delete PrimaryDataFileResource: " + file
							+ "\nReason" + e.toString());
		} catch (PrimaryDataDirectoryException e) {
			ClientDataManager.logger
					.error("Failed to delete PrimaryDataFileResource: " + file
							+ "\nReason" + e.toString());
		}

	}

	@Override
	public void moveTo(CollectionResource rDest, String name)
			throws ConflictException, NotAuthorizedException,
			BadRequestException {
		try {
			fileSystemHandler.removecache(file.getPath());
			// TODO handle unallowed names
			file.rename(name);
		} catch (RemoteException e) {
			ClientDataManager.logger.error("Failed to move/rename File: "
					+ e.toString());
		} catch (PrimaryDataEntityVersionException e) {
			ClientDataManager.logger.error("Failed to rename File: "
					+ e.toString());
		} catch (PrimaryDataDirectoryException e) {
			ClientDataManager.logger.error("Failed to move/rename File: "
					+ e.toString());
		}
	}
}
